package com.gitee.huxing.mybatis.core;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.transaction.TransactionException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.function.Supplier;

/**
 * @Description:
 * @ProjectName: JavaCourse
 * @Package: com.gitee.mybatis.core
 * @ClassName: MyBatisExceptionTranslator
 * @Author: huxing
 * @DateTime: 2021-09-16 下午2:39
 */
public class MyBatisExceptionTranslator implements PersistenceExceptionTranslator {

    private final Supplier<SQLExceptionTranslator> exceptionTranslatorSupplier;

    private SQLExceptionTranslator exceptionTranslator;

    /**
     * @Description:
     * @Author: huxing
     * @param dataSource
     * @param exceptionTranslatorLazyInit
     * @Date: 2021/9/16 下午2:45
     **/
    public MyBatisExceptionTranslator(DataSource dataSource, boolean exceptionTranslatorLazyInit){
        this(()->new SQLErrorCodeSQLExceptionTranslator(dataSource), exceptionTranslatorLazyInit);
    }

    public MyBatisExceptionTranslator(Supplier<SQLExceptionTranslator> exceptionTranslatorSupplier,
                                      boolean exceptionTranslatorLazyInit){
        this.exceptionTranslatorSupplier = exceptionTranslatorSupplier;
        if (!exceptionTranslatorLazyInit){
            this.initExceptionTranslator();
        }
    }

    @Override
    public DataAccessException translateExceptionIfPossible(RuntimeException e) {
        if (e instanceof PersistenceException){
            // Batch exceptions come inside another PersistenceException
            // recursion has a risk of infinite loop so better make another if
            if (e.getCause() instanceof PersistenceException){
                e = (PersistenceException) e.getCause();
            }
            if (e.getCause() instanceof SQLException){
                this.initExceptionTranslator();
                String task = e.getMessage() + "\n";
                SQLException se = (SQLException) e.getCause();
                DataAccessException dae = this.exceptionTranslator.translate(task, null, se);
                return dae != null ? dae : new UncategorizedSQLException(task, null, se);
            } else if (e.getCause() instanceof TransactionException){
                throw (TransactionException)e.getCause();
            }
            return new MyBatisSystemException(e);
        }
        return null;
    }

    /**
     * @Description: 初始化
     * @Author: huxing
     * @Date: 2021/9/16 下午2:47
     **/
    private synchronized void initExceptionTranslator(){
        if (this.exceptionTranslator == null){
            this.exceptionTranslator = exceptionTranslatorSupplier.get();
        }
    }
}
